/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "alsa_lib_render.h"

#define HDF_LOG_TAG HDF_AUDIO_HAL_LIB

#define MAX_PERIOD_SIZE (8 * 1024)
#define MIN_PERIOD_SIZE (4 * 1024)

static unsigned int g_bufferTime = 500000; /* ring buffer length in us */
static unsigned int g_periodTime = 100000; /* period time in us */
static snd_pcm_sframes_t g_bufferSize;
static snd_pcm_sframes_t g_periodSize;
static int g_resample       = 1;    /* enable alsa-lib resampling */
static int g_periodEvent    = 0;    /* produce poll event after each period */
static int g_canPause       = 0;    /* 0 Hardware doesn't support pause, 1 Hardware supports pause */

static int32_t GetHwParams(struct AudioCardInfo *cardIns, const struct AudioHwRenderParam *handleData)
{
    if (cardIns == NULL || handleData == NULL) {
        LOG_FUN_ERR("param is NULL!");
        return HDF_FAILURE;
    }

    cardIns->hwRenderParams.streamType = AUDIO_RENDER_STREAM;
    cardIns->hwRenderParams.channels = handleData->frameRenderMode.attrs.channelCount;
    cardIns->hwRenderParams.rate = handleData->frameRenderMode.attrs.sampleRate;
    cardIns->hwRenderParams.periodSize = handleData->frameRenderMode.periodSize;
    cardIns->hwRenderParams.periodCount = handleData->frameRenderMode.periodCount;
    cardIns->hwRenderParams.format = handleData->frameRenderMode.attrs.format;
    cardIns->hwRenderParams.period = handleData->frameRenderMode.attrs.period;
    cardIns->hwRenderParams.frameSize = handleData->frameRenderMode.attrs.frameSize;
    cardIns->hwRenderParams.isBigEndian = handleData->frameRenderMode.attrs.isBigEndian;
    cardIns->hwRenderParams.isSignedData = handleData->frameRenderMode.attrs.isSignedData;
    cardIns->hwRenderParams.startThreshold = handleData->frameRenderMode.attrs.startThreshold;
    cardIns->hwRenderParams.stopThreshold = handleData->frameRenderMode.attrs.stopThreshold;
    cardIns->hwRenderParams.silenceThreshold = handleData->frameRenderMode.attrs.silenceThreshold;
    return HDF_SUCCESS;
}

static int32_t AudioSetMixerVolume(snd_mixer_elem_t *pcmElemen, long vol)
{
    int32_t ret;

    if (pcmElemen == NULL) {
        LOG_FUN_ERR("AudioSetMixerVolume parameter is NULL!");
        return HDF_FAILURE;
    }

    // Judge whether it is mono or stereo
    if (snd_mixer_selem_is_playback_mono(pcmElemen)) {
        ret = snd_mixer_selem_set_playback_volume(pcmElemen, SND_MIXER_SCHN_FRONT_LEFT, vol);
        if (ret < 0) {
            LOG_FUN_ERR("AudioSetMixerVolume failed: %{public}s", snd_strerror(ret));
            return HDF_FAILURE;
        }
    } else {
        ret = snd_mixer_selem_set_playback_volume_all(pcmElemen, vol);
        if (ret < 0) {
            LOG_FUN_ERR("AudioSetMixerVolume failed: %{public}s", snd_strerror(ret));
            return HDF_FAILURE;
        }
    }

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderSetVolume(const struct DevHandle *handle, int cmdId,
    const struct AudioHwRenderParam *handleData)
{
    long vol;
    int32_t ret;
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioCtlRenderSetVolume parameter is NULL!");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }

    vol = (long)handleData->renderMode.ctlParam.volume;
    if (cardIns->ctrlLeftVolume != NULL) {
        ret = AudioSetMixerVolume(cardIns->ctrlLeftVolume, vol);
        if (ret < 0) {
            LOG_FUN_ERR("AudioSetMixerVolume left fail!");
            return HDF_FAILURE;
        }
    }

    if (cardIns->ctrlRightVolume != NULL) {
        ret = AudioSetMixerVolume(cardIns->ctrlRightVolume, vol);
        if (ret < 0) {
            LOG_FUN_ERR("AudioSetMixerVolume right fail!");
            return HDF_FAILURE;
        }
    }

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderGetVolume(const struct DevHandle *handle,
    int cmdId, struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    float vol;
    long volLeft;
    long volRight;
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioCtlRenderSetVolume parameter is NULL!");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL || cardIns->ctrlLeftVolume == NULL || cardIns->mixer == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }

    // Handling events
    ret = snd_mixer_handle_events(cardIns->mixer);
    if (ret < 0) {
        LOG_FUN_ERR("snd_mixer_handle_events fail!");
        return HDF_FAILURE;
    }

    // Left channel
    ret = snd_mixer_selem_get_playback_volume(cardIns->ctrlLeftVolume,
        SND_MIXER_SCHN_FRONT_LEFT, &volLeft);
    if (ret < 0) {
        LOG_FUN_ERR("Set left channel fail!");
        return HDF_FAILURE;
    }
    // right channel
    ret = snd_mixer_selem_get_playback_volume(cardIns->ctrlLeftVolume,
        SND_MIXER_SCHN_FRONT_RIGHT, &volRight);
    if (ret < 0) {
        LOG_FUN_ERR("Set right channel fail!");
        return HDF_FAILURE;
    }
    vol = (float)((volLeft + volRight) >> 1);
    handleData->renderMode.ctlParam.volume = vol;

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderSetPauseStu(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    int32_t pause;
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioCtlRenderSetVolume parameter is NULL!");
        return HDF_FAILURE;
    }

    if (g_canPause == 0) {
        /* The hardware does not support pause/resume,
         * so a success message is returned.
         * The software processing scheme is implemented
         * in AudioOutputRenderWrite interface.
        */
        return HDF_SUCCESS;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL || cardIns->renderPcmHandle == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }

    pause = handleData->renderMode.ctlParam.pause ?
        AUDIO_ALSALIB_IOCTRL_PAUSE : AUDIO_ALSALIB_IOCTRL_RESUME;
    if (pause == AUDIO_ALSALIB_IOCTRL_RESUME) {
        ret = snd_pcm_resume(cardIns->renderPcmHandle);
    } else {
        ret = snd_pcm_pause(cardIns->renderPcmHandle, pause);
    }
    if (ret < 0) {
        LOG_FUN_ERR("snd_pcm_pause fail!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t RenderSetMuteStuSub(struct AudioCardInfo *cardIns, int32_t muteState)
{
    int32_t ret;

    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }

    /** Mono (Front left alias) */
    if (cardIns->ctrlLeftVolume == NULL) {
        LOG_FUN_ERR("Unable to get Mono.");
        return HDF_FAILURE;
    }

    ret = snd_mixer_selem_has_playback_switch(cardIns->ctrlLeftVolume);
    if (ret == 1) { // 1: Controlled switch
        ret = snd_mixer_selem_set_playback_switch_all(cardIns->ctrlLeftVolume, muteState);
        if (ret < 0) {
            LOG_FUN_ERR("Unable to play mixer  switch ");
            return HDF_FAILURE;
        }
    } else { // 0: no control
        LOG_FUN_ERR("it's no control is present");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderSetMuteStu(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    bool muteState;
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioCtlRenderSetMuteStu parameter is NULL!");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }

    muteState = (bool)cardIns->renderMuteValue;
    if (strncmp(adapterName, PRIMARY, strlen(PRIMARY)) == 0) {
        if (muteState == false) {
            ret = AudioMixerSetCtrlMode(cardIns, adapterName, "Digital Playback mute",
                SND_PLAY_PATH, SND_OUT_CARD_OFF);
            if (ret < 0) {
                LOG_FUN_ERR("AudioMixerSetCtrlMode failed!");
                return HDF_FAILURE;
            }
        } else {
            ret = AudioMixerSetCtrlMode(cardIns, adapterName, "Digital Playback mute",
                SND_PLAY_PATH, SND_OUT_CARD_SPK_HP);
            if (ret < 0) {
                LOG_FUN_ERR("AudioMixerSetCtrlMode failed!");
                return HDF_FAILURE;
            }
        }
    }

    if (strncmp(adapterName, USB, strlen(USB)) == 0) {
        ret = RenderSetMuteStuSub(cardIns, (int32_t)muteState);
        if (ret < 0) {
            LOG_FUN_ERR("Render usb sound card SetMute failed!");
            return HDF_FAILURE;
        }
    }
    cardIns->renderMuteValue = (int32_t)handleData->renderMode.ctlParam.mute;

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderGetMuteStu(const struct DevHandle *handle,
    int cmdId, struct AudioHwRenderParam *handleData)
{
    struct AudioCardInfo *cardIns = NULL;
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioCtlRenderGetMuteStu parameter is NULL!");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }

    handleData->renderMode.ctlParam.mute = (bool)cardIns->renderMuteValue;

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderSetGainStu(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioCtlRenderSetGainStu parameter is NULL!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderGetGainStu(const struct DevHandle *handle,
    int cmdId, struct AudioHwRenderParam *handleData)
{
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("param is NULL!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderSceneSelect(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    struct AudioCardInfo *cardIns = NULL;
    enum AudioPortPin descPins;

    if (handle == NULL ||handleData == NULL) {
        LOG_FUN_ERR("AudioCtlRenderSceneSelect parameter is NULL!");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }

    descPins = handleData->renderMode.hwInfo.deviceDescript.pins;
    switch (descPins) {
        case PIN_OUT_SPEAKER:
            return AudioMixerSetCtrlMode(cardIns, adapterName,
                "Digital Playback Path", SND_PLAY_PATH, SND_OUT_CARD_SPK);
        case PIN_OUT_HEADSET:
            return AudioMixerSetCtrlMode(cardIns, adapterName,
                "Digital Playback Path", SND_PLAY_PATH, SND_OUT_CARD_HP);
        default:
            LOG_FUN_ERR("This mode is not currently supported!");
            break;
    }

    return HDF_FAILURE;
}

int32_t AudioCtlRenderSceneGetGainThreshold(const struct DevHandle *handle,
    int cmdId, struct AudioHwRenderParam *handleData)
{
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("param is NULL!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderGetVolThreshold(const struct DevHandle *handle,
    int cmdId, struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    long volMin = 0;
    long volMax = 0;
    struct AudioCardInfo *cardIns = NULL;

    if (handleData == NULL) {
        LOG_FUN_ERR("AudioCtlRenderGetVolThreshold parameter is NULL!");
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    ret = snd_mixer_selem_get_playback_volume_range(cardIns->ctrlLeftVolume, &volMin, &volMax);
    if (ret < 0) {
        LOG_FUN_ERR("snd_mixer_selem_get_playback_volume_range fail: %{public}s", snd_strerror(ret));
        (void)CloseMixerHandle(cardIns->mixer);
        CheckCardStatus(cardIns);
        (void)DestroyCardList();
        return HDF_FAILURE;
    }
    handleData->renderMode.ctlParam.volThreshold.volMin = (int)volMin;
    handleData->renderMode.ctlParam.volThreshold.volMax = (int)volMax;

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderSetChannelMode(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("param is NULL!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderGetChannelMode(const struct DevHandle *handle,
    int cmdId, struct AudioHwRenderParam *handleData)
{
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("param is NULL!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioCtlRenderSetAcodecMode(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("param is NULL!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioInterfaceLibCtlRender(const struct DevHandle *handle,
    int cmdId, struct AudioHwRenderParam *handleData)
{
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("paras is NULL!");
        return HDF_FAILURE;
    }

    if (cmdId < AUDIODRV_CTL_IOCTL_ELEM_INFO || cmdId > AUDIODRV_CTL_IOCTL_VOL_THRESHOLD_READ) {
        LOG_FUN_ERR("cmdId Not Supported!");
        return HDF_FAILURE;
    }

    switch (cmdId) {
        case AUDIODRV_CTL_IOCTL_ELEM_READ:
            return (AudioCtlRenderGetVolume(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_ELEM_WRITE:
            return (AudioCtlRenderSetVolume(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_MUTE_READ:
            return (AudioCtlRenderGetMuteStu(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_MUTE_WRITE:
            return (AudioCtlRenderSetMuteStu(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_CHANNEL_MODE_READ:
            return (AudioCtlRenderGetChannelMode(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_CHANNEL_MODE_WRITE:
            return (AudioCtlRenderSetChannelMode(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_GAIN_WRITE:
            return (AudioCtlRenderSetGainStu(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_GAIN_READ:
            return (AudioCtlRenderGetGainStu(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_SCENESELECT_WRITE:
            return (AudioCtlRenderSceneSelect(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_GAINTHRESHOLD_READ:
            return (AudioCtlRenderSceneGetGainThreshold(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_ACODEC_CHANGE_IN:
        case AUDIODRV_CTL_IOCTL_ACODEC_CHANGE_OUT:
            return (AudioCtlRenderSetAcodecMode(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_VOL_THRESHOLD_READ:
            return (AudioCtlRenderGetVolThreshold(handle, cmdId, handleData));
        default:
            LOG_FUN_ERR("Output Mode not support!");
            break;
    }

    return HDF_FAILURE;
}
static int32_t SetHWParamsSub(snd_pcm_t *handle, snd_pcm_hw_params_t *params, struct AudioPcmHwParams hwParams,
    snd_pcm_access_t access)
{
    int32_t ret;

    if (handle == NULL || params == NULL) {
        LOG_FUN_ERR("SetHWParamsSub parameter is null!");
        return HDF_FAILURE;
    }

    /* set hardware resampling */
    ret = snd_pcm_hw_params_set_rate_resample(handle, params, g_resample);
    if (ret < 0) {
        LOG_FUN_ERR("Resampling setup failed for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }
    /* set the interleaved read/write format */
    ret = snd_pcm_hw_params_set_access(handle, params, access);
    if (ret < 0) {
        LOG_FUN_ERR("Access type not available for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }
    /* set the sample format */
    ret = snd_pcm_hw_params_set_format(handle, params, hwParams.format);
    if (ret < 0) {
        LOG_FUN_ERR("Sample format not available for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }
    /* set the count of channels */
    ret = snd_pcm_hw_params_set_channels(handle, params, hwParams.channels);
    if (ret < 0) {
        LOG_FUN_ERR("Channels count (%u) not available for playbacks: %{public}s",
            hwParams.channels, snd_strerror(ret));
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t SetHWRate(snd_pcm_t *handle, snd_pcm_hw_params_t *params, uint32_t *rate)
{
    int32_t ret;
    uint32_t rRate;

    if (handle == NULL || params == NULL || rate == NULL) {
        LOG_FUN_ERR("SetHWParams parameter is null!");
        return HDF_FAILURE;
    }

    /* set the stream rate */
    rRate = *rate;
    ret = snd_pcm_hw_params_set_rate_near(handle, params, &rRate, 0);
    if (ret < 0) {
        LOG_FUN_ERR("Rate %uHz not available for playback: %{public}s", *rate, snd_strerror(ret));
        return HDF_FAILURE;
    }

    if (rRate != *rate) {
        ret = snd_pcm_hw_params_set_rate_near(handle, params, &rRate, 0);
        if (ret < 0) {
            LOG_FUN_ERR("Rate %uHz not available for playback: %{public}s", *rate, snd_strerror(ret));
            return HDF_FAILURE;
        }
    }
    /* Update to hardware supported rate */
    *rate = rRate;
    g_canPause = snd_pcm_hw_params_can_pause(params);

    return HDF_SUCCESS;
}
static int32_t SetHWParams(snd_pcm_t *handle, snd_pcm_hw_params_t *params,
    struct AudioPcmHwParams hwParams, snd_pcm_access_t access)
{
    int ret;
    int dir = 0; /* dir Value range (-1,0,1) */

    if (handle == NULL || params == NULL) {
        LOG_FUN_ERR("SetHWParams parameter is null!");
        return HDF_FAILURE;
    }

    snd_pcm_uframes_t size;
    ret = snd_pcm_hw_params_any(handle, params); // choose all parameters
    if (ret < 0) {
        LOG_FUN_ERR("No configurations available: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }
    if (SetHWParamsSub(handle, params, hwParams, access) < 0) {
        LOG_FUN_ERR("SetHWParamsSub failed!");
        return HDF_FAILURE;
    }
    if (SetHWRate(handle, params, &(hwParams.rate)) < 0) {
        LOG_FUN_ERR("SetHWRate failed!");
        return HDF_FAILURE;
    }
    ret = snd_pcm_hw_params_set_buffer_time_near(handle, params, &g_bufferTime, &dir);
    if (ret < 0) {
        LOG_FUN_ERR("Unable to set buffer time %{public}u for playback: %{public}s",
                    g_bufferTime, snd_strerror(ret));
        return HDF_FAILURE;
    }
    ret = snd_pcm_hw_params_get_buffer_size(params, &size);
    if (ret < 0) {
        LOG_FUN_ERR("Unable to get buffer size for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }
    g_bufferSize = size;
    ret = snd_pcm_hw_params_set_period_time_near(handle, params, &g_periodTime, &dir);
    if (ret < 0) {
        LOG_FUN_ERR("Unable to set period time %{public}u for playback: %{public}s",
                    g_bufferTime, snd_strerror(ret));
        return HDF_FAILURE;
    }
    ret = snd_pcm_hw_params_get_period_size(params, &size, &dir);
    if (ret < 0) {
        LOG_FUN_ERR("Unable to get period size for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }
    g_periodSize = size;
    ret = snd_pcm_hw_params(handle, params); // write the parameters to device
    if (ret < 0) {
        LOG_FUN_ERR("Unable to set hw params for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t SetSWParams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
{
    int32_t ret;

    if (handle == NULL || swparams == NULL) {
        LOG_FUN_ERR("SetHWParams parameter is null!");
        return HDF_FAILURE;
    }

    /* get the current swparams */
    ret = snd_pcm_sw_params_current(handle, swparams);
    if (ret < 0) {
        LOG_FUN_ERR("Unable to determine current swparams for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }
    /* start the transfer when the buffer is almost full: */
    /* (buffer_size / avail_min) * avail_min */
    if (g_periodSize == 0) {
        LOG_FUN_ERR("g_periodSize=0");
        return HDF_FAILURE;
    }
    ret = snd_pcm_sw_params_set_start_threshold(handle, swparams,
                                                (g_bufferSize / g_periodSize) * g_periodSize);
    if (ret < 0) {
        LOG_FUN_ERR("Unable to set start threshold mode for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }
    /* allow the transfer when at least period_size samples can be processed */
    /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
    ret = snd_pcm_sw_params_set_avail_min(handle, swparams, g_periodEvent ? g_bufferSize : g_periodSize);
    if (ret < 0) {
        LOG_FUN_ERR("Unable to set avail min for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }

    /* enable period events when requested */
    if (g_periodEvent) {
        ret = snd_pcm_sw_params_set_period_event(handle, swparams, 1);
        if (ret < 0) {
            LOG_FUN_ERR("Unable to set period event: %{public}s", snd_strerror(ret));
            return HDF_FAILURE;
        }
    }

    /* write the parameters to the playback device */
    ret = snd_pcm_sw_params(handle, swparams);
    if (ret < 0) {
        LOG_FUN_ERR("Unable to set sw params for playback: %{public}s", snd_strerror(ret));
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t AudioResetParams(snd_pcm_t *handle,
    struct AudioPcmHwParams audioHwParams, snd_pcm_access_t access)
{
    int32_t ret;
    snd_pcm_hw_params_t *hwParams = NULL;
    snd_pcm_sw_params_t *swParams = NULL;

    if (handle == NULL) {
        LOG_FUN_ERR("Handle is NULL!");
        return HDF_FAILURE;
    }

    snd_pcm_hw_params_alloca(&hwParams);
    snd_pcm_sw_params_alloca(&swParams);
    if ((ret = SetHWParams(handle, hwParams, audioHwParams, access)) < 0) {
        LOG_FUN_ERR("Setting of hwparams failed.");
        return HDF_FAILURE;
    }

    if ((ret = SetSWParams(handle, swParams)) < 0) {
        LOG_FUN_ERR("Setting of swparams failed.");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioOutputRenderHwParams(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    struct AudioCardInfo *cardIns = NULL;
    snd_pcm_hw_params_t *hwParams = NULL;
    snd_pcm_sw_params_t *swParams = NULL;

    if (handleData == NULL) {
        LOG_FUN_ERR("The parameter is empty");
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    ret = GetHwParams(cardIns, handleData);
    if (ret < 0) {
        LOG_FUN_ERR("GetHwParams error.");
        (void)CloseMixerHandle(cardIns->mixer);
        CheckCardStatus(cardIns);
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    snd_pcm_hw_params_alloca(&hwParams);
    snd_pcm_sw_params_alloca(&swParams);
    if ((ret = SetHWParams(cardIns->renderPcmHandle, hwParams, cardIns->hwRenderParams,
        SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        LOG_FUN_ERR("Setting of hwparams failed.");
        (void)CloseMixerHandle(cardIns->mixer);
        CheckCardStatus(cardIns);
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    if ((ret = SetSWParams(cardIns->renderPcmHandle, swParams)) < 0) {
        LOG_FUN_ERR("Setting of swparams failed.");
        (void)CloseMixerHandle(cardIns->mixer);
        CheckCardStatus(cardIns);
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioOutputRenderWrite(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    size_t sbufFrameSize;
    long frames;
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("The parameter is empty.");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL || cardIns->renderPcmHandle == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }

    if (g_canPause == 0) { /* Hardware does not support pause, enable soft solution */
        if (handleData->renderMode.ctlParam.pause) {
            LOG_FUN_ERR("Currently in pause, please check!");
            return HDF_FAILURE;
        }
    }

    if (!cardIns->renderMmapFlag) {
        ret = AudioResetParams(cardIns->renderPcmHandle, cardIns->hwRenderParams,
            SND_PCM_ACCESS_RW_INTERLEAVED);
        if (ret < 0) {
            LOG_FUN_ERR("AudioSetParamsMmap failed!");
            return HDF_FAILURE;
        }
        cardIns->renderMmapFlag = true;
    }

    /**Write interleaved frames to a PCM. */
    sbufFrameSize = (size_t)handleData->frameRenderMode.bufferFrameSize;
    frames = snd_pcm_writei(cardIns->renderPcmHandle,
                            handleData->frameRenderMode.buffer, sbufFrameSize);
    if (frames < 0) {
        frames = snd_pcm_recover(cardIns->renderPcmHandle, frames, 0);
    }
    if (frames < 0) {
        LOG_FUN_ERR("snd_pcm_writei failed: %{public}s", snd_strerror(frames));
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioOutputRenderPrepare(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    struct AudioCardInfo *cardIns = NULL;

    if (handleData == NULL) {
        LOG_FUN_ERR("The parameter is NULL!");
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    ret = snd_pcm_prepare(cardIns->renderPcmHandle);
    if (ret < 0) {
        LOG_FUN_ERR("snd_pcm_prepare fail: %{public}s", snd_strerror(ret));
        (void)CloseMixerHandle(cardIns->mixer);
        CheckCardStatus(cardIns);
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t InitMixerCtrlVolumeRange(struct AudioCardInfo *cardIns)
{
    int32_t ret;
    long volMin;
    long volMax;

    if (cardIns == NULL) {
        LOG_FUN_ERR("The parameter is NULL");
        return HDF_FAILURE;
    }
    /** cardIns->ctrlLeftVolume is Mono (Front left alias) */
    if (cardIns->ctrlLeftVolume == NULL && cardIns->ctrlRightVolume == NULL) {
        LOG_FUN_ERR("InitMixerCtrlVolumeRange error.");
        return HDF_FAILURE;
    }
    if (cardIns->ctrlLeftVolume != NULL) {
        ret = snd_mixer_selem_get_playback_volume_range(cardIns->ctrlLeftVolume, &volMin, &volMax);
        if (ret < 0) {
            LOG_FUN_ERR("Failed to get playback volume range: %{public}s", snd_strerror(ret));
            return HDF_FAILURE;
        }

        ret = snd_mixer_selem_set_playback_volume_range(cardIns->ctrlLeftVolume, MIN_VOLUME, MAX_VOLUME);
        if (ret < 0) {
            LOG_FUN_ERR("Failed to set playback volume range: %{public}s", snd_strerror(ret));
            return HDF_FAILURE;
        }
    }

    if (cardIns->ctrlRightVolume != NULL) {
        ret = snd_mixer_selem_get_playback_volume_range(cardIns->ctrlRightVolume, &volMin, &volMax);
        if (ret < 0) {
            LOG_FUN_ERR("Failed to get playback volume range");
            return HDF_FAILURE;
        }
        ret = snd_mixer_selem_set_playback_volume_range(cardIns->ctrlRightVolume, MIN_VOLUME, MAX_VOLUME);
        if (ret < 0) {
            LOG_FUN_ERR("Failed to set playback volume range");
            return HDF_FAILURE;
        }
    }

    return HDF_SUCCESS;
}

static int32_t InitMixerCtlElement(const char *adapterName,
    struct AudioCardInfo *cardIns, snd_mixer_t *mixer)
{
    int32_t ret;
    snd_mixer_elem_t *pcmElement = NULL;

    if (adapterName == NULL || cardIns == NULL || mixer == NULL) {
        LOG_FUN_ERR("The parameter is empty.");
        return HDF_FAILURE;
    }

    if (strncmp(adapterName, PRIMARY, strlen(PRIMARY)) == 0) {
        pcmElement = snd_mixer_first_elem(mixer);
        if (pcmElement == NULL) {
            LOG_FUN_ERR("snd_mixer_first_elem failed.");
            return HDF_FAILURE;
        }

        ret = GetPriMixerCtlElement(cardIns, pcmElement);
        if (ret < 0) {
            LOG_FUN_ERR("Capture GetPriMixerCtlElement failed.");
            return HDF_FAILURE;
        }
    } else if (strncmp(adapterName, USB, strlen(USB)) == 0) {
        cardIns->ctrlLeftVolume = AudioUsbFindElement(mixer);
    } else {
        LOG_FUN_ERR("The selected sound card not supported, please check!");
        return HDF_FAILURE;
    }

    ret = InitMixerCtrlVolumeRange(cardIns);
    if (ret < 0) {
        LOG_FUN_ERR("InitMixerCtrlVolumeRange failed!");
        return HDF_FAILURE;
    }

    ret = AudioMixerSetCtrlMode(cardIns, adapterName,
                                "Digital Playback Path",
                                SND_PLAY_PATH, SND_OUT_CARD_SPK_HP);
    if (ret < 0) {
        LOG_FUN_ERR("AudioMixerSetCtrlMode failed!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

/*
 * brief: Opens a PCM
 * param mode Open mode (see #SND_PCM_NONBLOCK, #SND_PCM_ASYNC)
 */
int32_t AudioOutputRenderOpen(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("The parameter is empty.");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = AudioGetCardInfo(adapterName, SND_PCM_STREAM_PLAYBACK);
    if (cardIns == NULL) {
        LOG_FUN_ERR("AudioRenderGetCardIns failed.");
        return HDF_FAILURE;
    }

    if (cardIns->renderPcmHandle != NULL) {
        LOG_FUN_ERR("Resource busy!!");
        return HDF_ERR_DEVICE_BUSY;
    }

    ret = snd_pcm_open(&cardIns->renderPcmHandle, cardIns->devName, SND_PCM_STREAM_PLAYBACK, 0);
    if (ret < 0) {
        LOG_FUN_ERR("AudioOutputRenderOpen fail: %{public}s!", snd_strerror(ret));
        CheckCardStatus(cardIns);
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    InitSound(&cardIns->mixer, cardIns->ctrlName);
    ret = InitMixerCtlElement(adapterName, cardIns, cardIns->mixer);
    if (ret < 0) {
        LOG_FUN_ERR("InitMixerCtlElement failed!");
        (void)CloseMixerHandle(cardIns->mixer);
        CheckCardStatus(cardIns);
        (void)DestroyCardList();
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioOutputRenderStop(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("The parameter is empty.");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL || cardIns->renderPcmHandle == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }
    /**For playback, snd_ pcm_ Drain will wait for all pending data frames to be broadcast before turning off PCM */
    ret = snd_pcm_drain(cardIns->renderPcmHandle);
    if (ret < 0) {
        LOG_FUN_ERR("AudioOutputRenderStop fail!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioOutputRenderClose(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioOutputRenderClose parameter is NULL!");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }

    if (cardIns->renderPcmHandle != NULL) {
        ret = snd_pcm_close(cardIns->renderPcmHandle);
        if (ret < 0) {
            LOG_FUN_ERR("snd_pcm_close fail: %{public}s", snd_strerror(ret));
        }
        cardIns->renderPcmHandle = NULL;
    }

    if (cardIns->cardStatus > 0) {
        cardIns->cardStatus -= 1;
    }
    if (cardIns->cardStatus == 0) {
        if (cardIns->mixer != NULL) {
            ret = snd_mixer_close(cardIns->mixer);
            if (ret < 0) {
                LOG_FUN_ERR("snd_mixer_close fail: %{public}s", snd_strerror(ret));
            }
            cardIns->mixer = NULL;
        }
        (void)memset_s(cardIns->cardName, MAX_CARD_NAME_LEN + 1, 0, MAX_CARD_NAME_LEN + 1);
        ret = DestroyCardList();
        if (ret != HDF_SUCCESS) {
            LOG_FUN_ERR("DestroyCardList failed, reason: %d.", ret);
            return ret;
        }
    }

    return HDF_SUCCESS;
}

int32_t AudioOutputRenderStart(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioOutputRenderStart parameter is NULL!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t RenderWriteiMmap(const struct AudioHwRenderParam *handleData, struct AudioCardInfo *cardIns)
{
    int32_t ret;
    uint32_t frameSize;
    uint32_t totalSize;
    uint32_t lastBuffSize;
    uint32_t loopTimes;
    uint32_t looper = 0;
    uint32_t copyLen = 0;
    int count = 0;
    struct AudioMmapBufferDescripter *mmapBufDesc = NULL;

    if (handleData == NULL || cardIns == NULL) {
        LOG_FUN_ERR("AudioOutputRenderReqMmapBuffer parameter is NULL!");
        return HDF_FAILURE;
    }

    frameSize = cardIns->hwRenderParams.channels * cardIns->hwRenderParams.format;
    if (frameSize == 0) {
        LOG_FUN_ERR("frame size = 0!");
        return HDF_FAILURE;
    }
    mmapBufDesc = (struct AudioMmapBufferDescripter *)&(handleData->frameRenderMode.mmapBufDesc);
    totalSize = (uint32_t)mmapBufDesc->totalBufferFrames * frameSize;
    lastBuffSize = ((totalSize % MIN_PERIOD_SIZE) == 0) ? MIN_PERIOD_SIZE : (totalSize % MIN_PERIOD_SIZE);
    loopTimes = (lastBuffSize == MIN_PERIOD_SIZE) ?
        (totalSize / MIN_PERIOD_SIZE) : (totalSize / MIN_PERIOD_SIZE + 1);
    while (looper < loopTimes) {
        copyLen = (looper < (loopTimes - 1)) ? MIN_PERIOD_SIZE : lastBuffSize;
        snd_pcm_uframes_t frames = (snd_pcm_uframes_t)(copyLen / frameSize);
        ret = snd_pcm_mmap_writei(cardIns->renderPcmHandle,
            (char *)mmapBufDesc->memoryAddress + mmapBufDesc->offset, frames);
        if (ret == -EAGAIN) {
            count++;
            if (count > AUDIO_ALSALIB_MMAP_MAX) {
                LOG_FUN_ERR("loop > max !");
                return HDF_FAILURE;
            }
            continue;
        }
        count = 0;
        if (ret < 0) {
            LOG_FUN_ERR("Write error: %{public}s\n", snd_strerror(ret));
            return HDF_FAILURE;
        }
        looper ++;
        mmapBufDesc->offset += copyLen;
        cardIns->renderMmapFrames += (uint64_t)frames;
    }

    return HDF_SUCCESS;
}

int32_t AudioOutputRenderReqMmapBuffer(const struct DevHandle *handle,
    int cmdId, const struct AudioHwRenderParam *handleData)
{
    int32_t ret;
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioOutputRenderReqMmapBuffer parameter is NULL!");
        return HDF_FAILURE;
    }
    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }
    cardIns->renderMmapFlag = false;

    ret = AudioResetParams(cardIns->renderPcmHandle,
        cardIns->hwRenderParams, SND_PCM_ACCESS_MMAP_INTERLEAVED);
    if (ret < 0) {
        LOG_FUN_ERR("AudioSetParamsMmap failed!");
        return HDF_FAILURE;
    }

    ret = RenderWriteiMmap(handleData, cardIns);
    if (ret < 0) {
        LOG_FUN_ERR("RenderWriteiMmap error!");
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

int32_t AudioOutputRenderGetMmapPosition(const struct DevHandle *handle,
    int cmdId, struct AudioHwRenderParam *handleData)
{
    struct AudioCardInfo *cardIns = NULL;

    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("AudioOutputRenderGetMmapPosition parameter is NULL!");
        return HDF_FAILURE;
    }

    const char *adapterName = handleData->renderMode.hwInfo.adapterName;
    cardIns = GetCardIns(adapterName);
    if (cardIns == NULL) {
        LOG_FUN_ERR("cardIns is NULL!");
        return HDF_FAILURE;
    }
    handleData->frameRenderMode.frames = cardIns->renderMmapFrames;

    return HDF_SUCCESS;
}

int32_t AudioInterfaceLibOutputRender(const struct DevHandle *handle,
    int cmdId, struct AudioHwRenderParam *handleData)
{
    int32_t ret;

    if (handle == NULL) {
        LOG_FUN_ERR("Input Render handle is NULL!");
        return HDF_FAILURE;
    }

    if (handle->object == NULL || handleData == NULL) {
        LOG_FUN_ERR("Input Render handle is error!");
        return HDF_FAILURE;
    }

    switch (cmdId) {
        case AUDIO_DRV_PCM_IOCTL_HW_PARAMS:
            ret = AudioOutputRenderHwParams(handle, cmdId, handleData);
            break;
        case AUDIO_DRV_PCM_IOCTL_WRITE:
            ret = AudioOutputRenderWrite(handle, cmdId, handleData);
            break;
        case AUDIO_DRV_PCM_IOCTRL_STOP:
            ret = AudioOutputRenderStop(handle, cmdId, handleData);
            break;
        case AUDIO_DRV_PCM_IOCTRL_START:
            ret = AudioOutputRenderStart(handle, cmdId, handleData);
            break;
        case AUDIO_DRV_PCM_IOCTL_PREPARE:
            ret = AudioOutputRenderPrepare(handle, cmdId, handleData);
            break;
        case AUDIO_DRV_PCM_IOCTRL_RENDER_CLOSE:
            ret = AudioOutputRenderClose(handle, cmdId, handleData);
            break;
        case AUDIO_DRV_PCM_IOCTRL_RENDER_OPEN:
            ret = AudioOutputRenderOpen(handle, cmdId, handleData);
            break;
        case AUDIODRV_CTL_IOCTL_PAUSE_WRITE:
            ret = AudioCtlRenderSetPauseStu(handle, cmdId, handleData);
            break;
        case AUDIO_DRV_PCM_IOCTL_MMAP_BUFFER:
            ret = AudioOutputRenderReqMmapBuffer(handle, cmdId, handleData);
            break;
        case AUDIO_DRV_PCM_IOCTL_MMAP_POSITION:
            ret = (AudioOutputRenderGetMmapPosition(handle, cmdId, handleData));
            break;
        default:
            LOG_FUN_ERR("Output Mode not support!");
            ret = HDF_FAILURE;
            break;
    }

    return ret;
}

int32_t AudioBindServiceRenderObject(struct DevHandle *handle, const char *name)
{
    int32_t ret;
    char *serviceName = NULL;
    struct HdfIoService *service = NULL;

    if (handle == NULL || name == NULL) {
        LOG_FUN_ERR("service name or handle is NULL!");
        return HDF_FAILURE;
    }

    serviceName = (char *)calloc(1, NAME_LEN);
    if (serviceName == NULL) {
        LOG_FUN_ERR("Failed to OsalMemCalloc serviceName");
        return HDF_FAILURE;
    }

    ret = snprintf_s(serviceName, NAME_LEN - 1,
        SERVIC_NAME_MAX_LEN + 1, "hdf_audio_%s", name);
    if (ret < 0) {
        LOG_FUN_ERR("Failed to snprintf_s");
        AudioMemFree((void **)&serviceName);
        return HDF_FAILURE;
    }

    service = HdfIoServiceBindName(serviceName);
    if (service == NULL) {
        LOG_FUN_ERR("Failed to get service!");
        AudioMemFree((void **)&serviceName);
        return HDF_FAILURE;
    }
    AudioMemFree((void **)&serviceName);
    handle->object = service;

    return HDF_SUCCESS;
}

/* CreatRender for Bind handle */
struct DevHandle *AudioBindServiceRender(const char *name)
{
    int32_t ret;
    struct DevHandle *handle = NULL;

    if (name == NULL) {
        LOG_FUN_ERR("service name NULL!");
        return NULL;
    }

    handle = (struct DevHandle *)calloc(1, sizeof(struct DevHandle));
    if (handle == NULL) {
        LOG_FUN_ERR("Failed to OsalMemCalloc handle");
        return NULL;
    }

    ret = AudioBindServiceRenderObject(handle, name);
    if (ret != HDF_SUCCESS) {
        LOG_FUN_ERR("handle->object is NULL!");
        AudioMemFree((void **)&handle);
        return NULL;
    }
    LOG_PARA_INFO("BIND SERVICE SUCCESS!");

    return handle;
}

void AudioCloseServiceRender(const struct DevHandle *handle)
{
    if (handle != NULL) {
        if (handle->object == NULL) {
            LOG_FUN_ERR("Render handle or handle->object is NULL");
        }
        AudioMemFree((void **)&handle);
    }
}

int32_t AudioInterfaceLibModeRender(const struct DevHandle *handle,
    struct AudioHwRenderParam *handleData, int cmdId)
{
    if (handle == NULL || handleData == NULL) {
        LOG_FUN_ERR("paras is NULL!");
        return HDF_FAILURE;
    }

    switch (cmdId) {
        case AUDIO_DRV_PCM_IOCTL_HW_PARAMS:
        case AUDIO_DRV_PCM_IOCTL_WRITE:
        case AUDIO_DRV_PCM_IOCTRL_STOP:
        case AUDIO_DRV_PCM_IOCTRL_START:
        case AUDIO_DRV_PCM_IOCTL_PREPARE:
        case AUDIODRV_CTL_IOCTL_PAUSE_WRITE:
        case AUDIO_DRV_PCM_IOCTL_MMAP_BUFFER:
        case AUDIO_DRV_PCM_IOCTL_MMAP_POSITION:
        case AUDIO_DRV_PCM_IOCTRL_RENDER_OPEN:
        case AUDIO_DRV_PCM_IOCTRL_RENDER_CLOSE:
            return (AudioInterfaceLibOutputRender(handle, cmdId, handleData));
        case AUDIODRV_CTL_IOCTL_ELEM_WRITE:
        case AUDIODRV_CTL_IOCTL_ELEM_READ:
        case AUDIODRV_CTL_IOCTL_MUTE_WRITE:
        case AUDIODRV_CTL_IOCTL_MUTE_READ:
        case AUDIODRV_CTL_IOCTL_GAIN_WRITE:
        case AUDIODRV_CTL_IOCTL_GAIN_READ:
        case AUDIODRV_CTL_IOCTL_CHANNEL_MODE_WRITE:
        case AUDIODRV_CTL_IOCTL_CHANNEL_MODE_READ:
        case AUDIODRV_CTL_IOCTL_SCENESELECT_WRITE:
        case AUDIODRV_CTL_IOCTL_GAINTHRESHOLD_READ:
        case AUDIODRV_CTL_IOCTL_ACODEC_CHANGE_IN:
        case AUDIODRV_CTL_IOCTL_ACODEC_CHANGE_OUT:
        case AUDIODRV_CTL_IOCTL_VOL_THRESHOLD_READ:
            return (AudioInterfaceLibCtlRender(handle, cmdId, handleData));
        default:
            LOG_FUN_ERR("Mode Error!");
            break;
    }
    return HDF_ERR_NOT_SUPPORT;
}
